package model

import (
	"errors"
	"fmt"
	"github.com/jinzhu/gorm"
	"github.com/sirupsen/logrus"
	api2 "smart-sensor-cloud/internal/api"
	"smart-sensor-cloud/pkg/fsm"
	//"smart-sensor-cloud/internal/model"
)

const (
	DeviceContextKey            = "smart-sensor-cloud/device"       // Device结构在FSM Context中的Key常量
	DeviceActionErrorContextKey = "smart-sensor-cloud/device/error" // Device事件动作错误Key常量
	DBHandlerContextKey         = "smart-sensor-cloud/db"           // 数据库句柄Context Key
	APIClientContextKey         = "smart-sensor-cloud/api/client"   // API客户端句柄Context Key

	DeviceStatusRecorded          = "RECORDED"           // 已录入平台
	DeviceStatusInstalled         = "INSTALLED"          // 已实地安装
	DeviceStatusUploaded          = "UPLOADED"           // 已上图市局
	DeviceStatusSceneAssociated   = "SCENE_ASSOCIATED"   // 已关联场景
	DeviceStatusSceneUnbound      = "SCENE_UNBOUND"      // 已解除场景
	DeviceStatusAccountAssociated = "ACCOUNT_ASSOCIATED" // 已关联台帐
	DeviceStatusAccountUnbound    = "ACCOUNT_UNBOUND"    // 已解绑台帐
	DeviceStatusEnabled           = "ENABLED"            // 已启用
	DeviceStatusDisabled          = "DISABLED"           // 已停用
	DeviceStatusDownloaded        = "DOWNLOADED"         // 已下图市局
	DeviceStatusDeleted           = "DELETED"            // 已删除

	DeviceEventInitDeleted              = "INIT_DELETED"                //预导入删除
	DeviceEventWebConfirmed             = "WEB_CONFIRMED"               // Web端手工确认
	DeviceEventAppConfirmed             = "APP_CONFIRMED"               // App校验安装点位
	DeviceEventAddDeviceToPlatform      = "ADD_DEVICE_TO_PLATFORM"      // 市局平台新增设备
	DeviceEventRemoveDeviceFromPlatform = "REMOVE_DEVICE_FROM_PLATFORM" // 删除设备
	DeviceEventReviewRemoveAction       = "REVIEW_REMOVE_ACTION"        // 复核删除操作
	DeviceEventChangePTInfo             = "CHANGE_PT_INFO"              // 修改点位信息
	DeviceEventBindScene                = "BIND_SCENE"                  // 绑定场景
	DeviceEventUnboundScene             = "UNBOUND_SCENE"               // 解除场景
	DeviceEventAssociationAccount       = "ASSOCIATION_ACCOUNT"         // 关联台帐
	DeviceEventUnboundAccount           = "UNBOUND_ACCOUNT"             // 解绑台帐
	DeviceEventEnable                   = "ENABLE"                      // 启用
	DeviceEventDisable                  = "DISABLE"                     // 停用
)

var (
	ErrDeviceNotFoundInContext    = errors.New("无法从上下文中获取设备信息")
	ErrDBHandlerNotFoundInContext = errors.New("无法从上下文中获取数据库句柄")
	ErrAPIClientNotFoundInContext = errors.New("无法从上下文中获取API客户端句柄")

	transitions = []*fsm.Transition{
		{DeviceStatusRecorded, DeviceStatusDeleted, DeviceEventInitDeleted, initDeleted()},
		{DeviceStatusRecorded, DeviceStatusInstalled, DeviceEventWebConfirmed, webConfirm()},
		{DeviceStatusRecorded, DeviceStatusInstalled, DeviceEventAppConfirmed, appConfirm()},
		{DeviceStatusInstalled, DeviceStatusUploaded, DeviceEventAddDeviceToPlatform, addDeviceToPlatform()},
		{DeviceStatusUploaded, DeviceStatusSceneAssociated, DeviceEventBindScene, nil},
		{DeviceStatusSceneAssociated, DeviceStatusSceneUnbound, DeviceEventUnboundScene, nil},
		{DeviceStatusSceneAssociated, DeviceStatusAccountAssociated, DeviceEventAssociationAccount, nil},
		{DeviceStatusAccountAssociated, DeviceStatusEnabled, DeviceEventEnable, nil},
		{DeviceStatusEnabled, DeviceStatusDisabled, DeviceEventDisable, nil},
		{DeviceStatusDisabled, DeviceStatusAccountUnbound, DeviceEventUnboundAccount, nil},
		{DeviceStatusAccountUnbound, DeviceStatusSceneUnbound, DeviceEventUnboundScene, nil},
		{DeviceStatusSceneUnbound, DeviceStatusUploaded, DeviceEventChangePTInfo, nil},
		{DeviceStatusUploaded, DeviceStatusDownloaded, DeviceEventRemoveDeviceFromPlatform, nil},
		{DeviceStatusDownloaded, DeviceStatusDeleted, DeviceEventReviewRemoveAction, nil},
	}
)

type (
	DeviceStatusDelegate struct {
	}
)

func (d *DeviceStatusDelegate) AfterTransitionCausedError(from, to, event string, ctx *fsm.Context) {
	logrus.WithFields(logrus.Fields{
		"device": ctx.Get(DeviceContextKey),
		"from":   from,
		"to":     to,
		"event":  event,
	}).Errorf("设备状态转换事件被触发, 对应动作执行期间出现错误: %s", ctx.Get(DeviceActionErrorContextKey).(error).Error())
}

func (d *DeviceStatusDelegate) BeforeTransitionBegin(from, to, event string, ctx *fsm.Context) {
}

func (d *DeviceStatusDelegate) AfterTransitionCompleted(from, to, event string, ctx *fsm.Context) {
	logrus.WithFields(logrus.Fields{
		"device": ctx.Get(DeviceContextKey),
		"from":   from,
		"to":     to,
		"event":  event,
	}).Infof("设备状态转换事件被触发, 对应动作执行成功")
}

func (d *DeviceStatusDelegate) AfterTransitionEnd(from, to, event string, ctx *fsm.Context) {
}

func (d *DeviceStatusDelegate) AfterTransitionDeclined(from, to, event string, ctx *fsm.Context) {
}

func (d *DeviceStatusDelegate) BeforeActionInvoked(from, to, event string, ctx *fsm.Context) {
	logrus.WithFields(logrus.Fields{
		"device": ctx.Get(DeviceContextKey),
		"from":   from,
		"to":     to,
		"event":  event,
	}).Infof("设备状态转换事件被触发, 对应动作即将被执行")
}

func (d *DeviceStatusDelegate) AfterActionInvoked(from, to, event string, ctx *fsm.Context) {
	logrus.WithFields(logrus.Fields{
		"device": ctx.Get(DeviceContextKey),
		"from":   from,
		"to":     to,
		"event":  event,
	}).Infof("设备状态转换事件被触发, 对应动作执行完毕")
}

func (d *DeviceStatusDelegate) HandleEvent(action fsm.ActionHandler, from, to, event string, ctx *fsm.Context) error {
	defer d.AfterTransitionEnd(from, to, event, ctx)
	if from != to {
		d.BeforeTransitionBegin(from, to, event, ctx)
	}

	d.BeforeActionInvoked(from, to, event, ctx)
	err := action(from, to, event, ctx)
	d.AfterActionInvoked(from, to, event, ctx)
	if err != nil {
		ctx.Set(DeviceActionErrorContextKey, err)
		d.AfterTransitionCausedError(from, to, event, ctx)
		return err
	} else {
		d.AfterTransitionCompleted(from, to, event, ctx)
		return nil
	}
}

func NewDeviceFSM() *fsm.StateMachine {
	return fsm.New(
		&DeviceStatusDelegate{},
		transitions...,
	)
}

func initDeleted() fsm.ActionHandler {
	return func(from, to, event string, ctx *fsm.Context) error {
		v := ctx.Get(DeviceContextKey)
		if v == nil {
			return ErrDeviceNotFoundInContext
		}
		device := v.(*Device)
		device.PlatformStatus = to

		db := ctx.Get(DBHandlerContextKey)
		if db == nil {
			return ErrDBHandlerNotFoundInContext
		}

		tx := db.(*gorm.DB)

		if err := tx.Model(device).Update("platform_status", to).Error; err != nil {
			return fmt.Errorf("更新数据库中设备状态失败, %w", err)
		}

		return nil
	}
}

func webConfirm() fsm.ActionHandler {
	return func(from, to, event string, ctx *fsm.Context) error {
		v := ctx.Get(DeviceContextKey)
		if v == nil {
			return ErrDeviceNotFoundInContext
		}
		device := v.(*Device)
		device.PlatformStatus = to

		db := ctx.Get(DBHandlerContextKey)
		if db == nil {
			return ErrDBHandlerNotFoundInContext
		}

		tx := db.(*gorm.DB)

		if err := tx.Model(device).Update("platform_status", to).Error; err != nil {
			return fmt.Errorf("更新数据库中设备状态失败, %w", err)
		}

		return nil
	}
}

func appConfirm() fsm.ActionHandler {
	return func(from, to, event string, ctx *fsm.Context) error {
		v := ctx.Get(DeviceContextKey)
		if v == nil {
			return ErrDeviceNotFoundInContext
		}
		device := v.(*Device)
		device.PlatformStatus = to

		db := ctx.Get(DBHandlerContextKey)
		if db == nil {
			return ErrDBHandlerNotFoundInContext
		}

		tx := db.(*gorm.DB)

		if err := tx.Model(device).Update("platform_status", to).Error; err != nil {
			return fmt.Errorf("更新数据库中设备状态失败, %w", err)
		}

		return nil
	}
}

func addDeviceToPlatform() fsm.ActionHandler {
	return func(from, to, event string, ctx *fsm.Context) error {
		v := ctx.Get(DeviceContextKey)
		if v == nil {
			return ErrDeviceNotFoundInContext
		}
		device := v.(*Device)

		api := ctx.Get(APIClientContextKey)
		if api == nil {
			return ErrAPIClientNotFoundInContext
		}
		client := api.(*api2.Client)

		if resp, err := client.AddDevice(&api2.AddDeviceReq{
			OriginNo:  device.DeviceNo,
			Name:      device.Name,
			TypeID:    fmt.Sprintf("%d", device.TypeID),
			SectionID: device.SectionID,
		}); err != nil {
			return fmt.Errorf("调用添加设备接口出现错误, %w", err)
		} else if resp.Code != "200" {
			return fmt.Errorf("调用添加设备接口返回失败, 错误码: %s, 错误信息: %s", resp.Code, resp.Message)
		}

		return nil
	}
}
